import json

from carts.utils import merge_cookie_redis_cart
from celery_tasks.email.tasks import send_verify_url
from django.contrib.auth import authenticate, login, logout
from django_redis import get_redis_connection
import re
from django import http
from django.shortcuts import render, redirect
from django.views import View

from meiduo_mall.utils.email import generate_verify_url, decode_token
from meiduo_mall.utils.login_required import MyLoginRequest
from users.models import User, Address
from verifies.libs.captcha.captcha import Captcha
from django.conf import settings

from django.core.mail import send_mail

from meiduo_mall.utils.constants import Code
from itsdangerous import TimedJSONWebSignatureSerializer as TJWSSerializer


class UserRegisterView(View):

    def get(self, request):

        return render(request, 'register.html')

    def post(self, request):
        # print(request.POST)
        data = request.POST
        # 1 获取数据
        # submit 提交
        user_name = data.get('user_name')
        pwd = data.get('pwd')
        cpwd = data.get('cpwd')
        phone = data.get('phone')
        pic_code = data.get('pic_code')
        msg_code = data.get('msg_code')
        allow = data.get('allow')

        # 2 判断是否为空
        if not all([user_name, pwd, cpwd, phone, allow, pic_code, msg_code]):
            return http.HttpResponseBadRequest('参数不全')

        # 3 判断用户名是否重复，是否同意协议，判断两次密码是否相同
        # 3.1判断密码格式是否正确，
        if not re.match('^[0-9A-Za-z]{8,20}$', pwd):
            return http.HttpResponseBadRequest("密码格式不正确")

        # 3.2两次密码是否相同
        if pwd != cpwd:
            return http.HttpResponseBadRequest('两次密码填写不相同')

            # 3.3判断是否已经同意协议
        if allow != 'on':
            return http.HttpResponseBadRequest('未同意协议，无法注册')

            # 3.4判断用户名格式
        if not re.match('^[a-zA-Z0-9_-]{5,20}$', user_name):
            return http.HttpResponseBadRequest('用户名格式不正确')

            # 3.5判断用户名是否已存在
            # 3.6手机号格式校验
        if not re.match('^1[3-9]\d{9}$', phone):
            return http.HttpResponseBadRequest('手机号格式不正确')
            # 3.7校验手机验证码
        redis_conn = get_redis_connection('verify_code')
        redis_phone_code = redis_conn.get('sms_code_%s' % phone)
        if redis_phone_code == None:
            return render(request, 'register.html', {'error_sms_msg': '手机验证码已过期'})

        if redis_phone_code.decode() != msg_code:
            return render(request, 'register.html', {'error_sms_msg': '手机验证码错误'})
        # 4 保存数据

        user = User.objects.create_user(username=user_name, password=pwd, mobile=phone)

        login(request, user)
        rsp = redirect('/')
        rsp.set_cookie('username', user.username)

        # 5 成功后返回页面
        return rsp


class CheckUserNameView(View):

    def get(self, request, username):
        # 判断是用户名是否已经存在
        count = User.objects.filter(username=username).count()

        return http.JsonResponse({'count': count})


class CheckPhoneNubView(View):

    def get(self, request, phone):
        count = User.objects.filter(mobile=phone).count()

        return http.JsonResponse({'count': count})


class UserLoginView(View):

    def get(self, request):

        return render(request, 'login.html')

    def post(self, request):

        # 1 获得数据
        data = request.POST
        username = data.get('username')
        pwd = data.get('pwd')
        print(username, pwd)

        # 2 判断是否为空
        if not all([username, pwd]):
            return http.HttpResponseForbidden('参数不全')

        # 3 用户名格式判断,密码格式验证
        if not re.match('^[a-zA-Z0-9_-]{5,20}$', username):
            return http.HttpResponseForbidden('用户名格式错误')

        if not re.match('^[0-9A-Za-z]{8,20}$', pwd):
            return http.HttpResponseForbidden('密码格式错误')

        # 4 校验帐号密码的正确性
        user = authenticate(request=request, username=username, password=pwd)
        if not user:
            return http.HttpResponseForbidden('用户名或密码错误')

        # 5 状态保持
        login(request, user)  # 记录用户信息到session
        if data.get('remembered') == 'on':
            request.session.set_expiry(3600 * 24 * 2)
        else:
            request.session.set_expiry(0)

        rsp = redirect('/')
        rsp.set_cookie('username', user.username, max_age=3600 * 24 * 2)
        rsp = merge_cookie_redis_cart(request, rsp, user)
        return rsp


class UserCenterInfoView(MyLoginRequest):
    def get(self, request):
        user = request.user

        content = {
            'username': user.username,
            'mobile': user.mobile,
            'email': user.email,
            'email_active': user.email_active
        }
        return render(request, 'user_center_info.html', context=content)


class EmailView(MyLoginRequest):
    def put(self, request):
        # 获取参数
        data = json.loads(request.body.decode())
        email = data.get('email')
        # 校验参数
        if not email:
            return http.JsonResponse({'code': Code.Parameter_Error})
        '''
        subject 邮件标题
        message 普通邮件正文，普通字符串
        from_email 发件人
        recipient_list 收件人列表
        html_message 多媒体邮件正文，可以是html字符串
        '''
        verify_url = generate_verify_url(request.user)

        send_verify_url.delay(email, verify_url)

        # 入库
        request.user.email = email
        request.user.save()

        return http.JsonResponse({'code': Code.OK})

    def get(self, request):
        # 获取参数
        token = request.GET.get('token')

        # 校验参数
        if not token:
            return http.HttpResponseForbidden('参数不全')
        user = decode_token(token)

        if not user:
            return http.HttpResponseForbidden('token失效')
        user.email_active = True
        user.save()

        return redirect('/')


# 收货地址
class AddressView(MyLoginRequest):
    def get(self, request):
        addresses = request.user.addresses.all()
        _addresses = []
        for address in addresses:
            if address.is_deleted:
                continue
            _addresses.append(
                {
                    'id': address.id,
                    "title": address.title,
                    "receiver": address.receiver,
                    "province_id": address.province_id,
                    "city_id": address.city_id,
                    "district_id": address.district_id,
                    "place": address.place,
                    "mobile": address.mobile,
                    "tel": address.tel,
                    "email": address.email,
                    "province": address.province.name,
                    "city": address.city.name,
                    "district": address.district.name,
                }
            )

        content = {'addresses': _addresses, 'user': {'default_address_id': request.user.default_address_id}}
        return render(request, 'user_center_site.html', context=content)


class CreateAddressView(MyLoginRequest):

    def post(self, request):
        # 获取参数
        data_dic = json.loads(request.body.decode())
        # 校验参数
        title = data_dic.get('title')
        receiver = data_dic.get('receiver')
        province_id = data_dic.get('province_id')
        city_id = data_dic.get('city_id')
        district_id = data_dic.get('district_id')
        place = data_dic.get('place')
        mobile = data_dic.get('mobile')
        tel = data_dic.get('tel')
        email = data_dic.get('email')

        if not all([title, receiver, province_id, city_id, district_id, place, mobile, tel, email]):
            return http.HttpResponseForbidden('参数不全')

        # 数据入库
        data_dic['user'] = request.user
        address = Address.objects.create(**data_dic)
        # 数据拼接返回响应
        content = {
            'code': Code.OK,
            'address': {
                'id': address.id,
                "title": address.title,
                "receiver": address.receiver,
                "province_id": address.province_id,
                "city_id": address.city_id,
                "district_id": address.district_id,
                "place": address.place,
                "mobile": address.mobile,
                "tel": address.tel,
                "email": address.email,
                "province": address.province.name,
                "city": address.city.name,
                "district": address.district.name,
            }
        }
        return http.JsonResponse(content)
        # 返回响应


class AddressUpdateView(MyLoginRequest):

    def put(self, request, area_id):
        data_dic = json.loads(request.body.decode())
        # Address.objects.filter(id=area_id).update(**data)
        address = Address.objects.get(id=area_id)
        address.title = data_dic.get('title')
        address.receiver = data_dic.get('receiver')
        address.province_id = data_dic.get('province_id')
        address.city_id = data_dic.get('city_id')
        address.district_id = data_dic.get('district_id')
        address.place = data_dic.get('place')
        address.mobile = data_dic.get('mobile')
        address.tel = data_dic.get('tel')
        address.email = data_dic.get('email')
        address.save()

        content = {
            'code': Code.OK,
            'address': {
                'id': data_dic.get('id'),
                "title": data_dic.get('title'),
                "receiver": data_dic.get('receiver'),
                "province_id": data_dic.get('province_id'),
                "city_id": data_dic.get('city_id'),
                "district_id": data_dic.get('district_id'),
                "place": data_dic.get('place'),
                "mobile": data_dic.get('mobile'),
                "tel": data_dic.get('tel'),
                "email": data_dic.get('email'),
                "province": data_dic.get('province'),
                "city": data_dic.get('city'),
                "district": data_dic.get('district')
            }
        }
        return http.JsonResponse(content)

    def delete(self, request, area_id):
        Address.objects.filter(id=area_id).update(is_deleted=True)
        return http.JsonResponse({'code': Code.OK})


class SetDefaultAddressView(MyLoginRequest):

    def put(self, request, area_id):
        request.user.default_address_id = area_id
        request.user.save()
        return http.JsonResponse({'code': Code.OK})
        pass


class SetAddressTitleView(MyLoginRequest):
    def put(self, request, area_id):
        data = json.loads(request.body.decode())
        title = data.get('title')
        Address.objects.filter(id=area_id).update(title=title)
        return http.JsonResponse({'code': Code.OK})


class ModifyPasswordView(MyLoginRequest):
    def get(self, request):
        return render(request, 'user_center_pass.html')

    def post(self, request):
        data = request.POST
        old_pwd = data.get('old_pwd')
        new_pwd = data.get('new_pwd')
        new_cpwd = data.get('new_cpwd')

        if not all([old_pwd, new_pwd, new_cpwd]):
            return http.HttpResponseForbidden('参数不全')

        if not request.user.check_password(old_pwd):
            return http.HttpResponseForbidden('旧密码不正确')

        if new_pwd != new_cpwd:
            return http.HttpResponseForbidden('两次密码输入不相同')

        request.user.set_password(new_pwd)
        request.user.save()
        rsp = redirect('/login')
        logout(request)
        rsp.delete_cookie('username')
        return rsp


class FindPasswordView(View):
    def get(self, request):
        return render(request, 'find_password.html')


class FindPWDFirstView(View):
    def get(self, request, username):
        data_dict = request.GET
        image_code = data_dict.get('image_code')
        image_code_id = data_dict.get('image_code_id')

        if not all([username, image_code, image_code_id]):
            return http.JsonResponse({'errormsg': '参数不全'}, status=400)

        redis_conn = get_redis_connection('verify_code')
        redis_img_code = redis_conn.get('img_code_%s' % image_code_id)
        # 检验图片验证码是否过期
        if not redis_img_code:
            return http.JsonResponse({'code': '4001', 'errmsg': '验证码已过期'}, status=400)
        redis_img_code = redis_img_code.decode().lower()
        redis_conn.delete('img_code_%s' % image_code_id)

        if image_code != redis_img_code:
            return http.JsonResponse({'code': '4001', 'errmsg': '验证码输入错误'}, status=400)

        try:
            user = User.objects.get(username=username)
            mobile = user.mobile
            if not mobile:
                mobile = username
            if not re.match('^1[345789]\d{9}$'):
                return http.JsonResponse({'errormsg': '帐号未绑定手机'}, status=400)
        except:
            try:
                user = User.objects.get(mobile=username)
                mobile = user.mobile
            except:
                return http.JsonResponse({}, status=404)

        access_token = {
            'user_name': user.username,
            'user_id': user.id
        }

        serializer = TJWSSerializer(settings.SECRET_KEY, expires_in=300)
        access_token = serializer.dumps(access_token).decode()

        return http.JsonResponse({'mobile': mobile, 'access_token': access_token})


class FindPWDSecondView(View):
    def get(self, request, username):
        # 获取参数
        data_dict = request.GET
        sms_code = data_dict.get('sms_code')
        mobile = data_dict.get('mobile')
        # 校验参数
        if not all([sms_code, mobile]):
            return http.JsonResponse({'errormsg': '参数不全'}, status=403)
        redis_conn = get_redis_connection('verify_code')
        redis_phone_code = redis_conn.get('sms_code_%s' % mobile)
        if redis_phone_code == None:
            return render(request, 'register.html', {'error_sms_msg': '手机验证码已过期'}, status=400)

        if redis_phone_code.decode() != sms_code:
            return render(request, 'register.html', {'error_sms_msg': '手机验证码错误'}, status=400)

        try:
            user = User.objects.get(username=username)
            if user.mobile != mobile:
                return http.JsonResponse({'errormsg': '用户手机号不正确'}, status=403)
        except:
            return http.JsonResponse({'errormsg': '用户不存在'}, status=404)

        access_token = {
            'user_id': user.id,
            'mobile': user.mobile
        }

        serializer = TJWSSerializer(settings.SECRET_KEY, expires_in=300)
        access_token = serializer.dumps(access_token).decode()

        content = {
            'user_id': user.id,
            'access_token': access_token
        }

        return http.JsonResponse(content)


class FindPWDThreeView(View):
    def post(self, request, user_id):
        # 获取数据
        data_dict = json.loads(request.body.decode())
        password = data_dict.get('password')
        password2 = data_dict.get('password2')
        access_token = data_dict.get('access_token')

        # 校验数据
        if not all([password, password2, access_token]):
            return http.JsonResponse({'message': '数据不全'}, status=400)

        serializer = TJWSSerializer(settings.SECRET_KEY, expires_in=300)
        try:
            access_token = serializer.loads(access_token.encode())
        except:
            http.JsonResponse({'message': 'access_token已过期'})

        token_id = access_token.get('user_id')
        if user_id != token_id:
            http.JsonResponse({'message': "修改用户不相符"}, status=400)

        if password != password2:
            http.JsonResponse({'message': '两次密码不相同'}, status=400)

        try:
            user = User.objects.get(id=user_id)
        except:
            return http.JsonResponse({'message': '用户不存在'})

        # 数据入库
        user.set_password(password)
        user.save()

        return http.JsonResponse({})

